/**
 * 
 */
package profile.aspect;

import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLWarning;
import java.sql.Statement;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @author dtran091109
 *
 */
@Aspect
public abstract class SQLAspect {
	
	private SQLExecuteContexts contexts = new SQLExecuteContexts();
	
	@Pointcut
	public abstract void afterOpenNewConnectionPointcut();
	
	@Around("afterOpenNewConnectionPointcut()")
	public Object afterOpenNewConnectionAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		//System.out.println("after get connection");
		Connection con = (Connection) joinPoint.proceed();
		contexts.enableStats(con);
		return con;
	}	
	
	/*@Pointcut
	public abstract void afterCreateStatementPointcut();
	
	@Around("afterCreateStatementPointcut()")
	public Object afterCreateStatementAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		Statement stmt = (Statement) joinPoint.proceed();
		contexts.addStatement(stmt);
		return stmt;
	}*/
	
	@Pointcut
	public abstract void beforeStatementExecutePointcut();
	
	@Around("beforeStatementExecutePointcut()")
	public Object beforeStatementExecuteAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		String sql = (String) joinPoint.getArgs()[0];
		Statement stmt = (Statement) joinPoint.getTarget();
		contexts.addStatement(stmt, sql);
		
		return joinPoint.proceed();
	}
	
	@Pointcut
	public abstract void aroundPrepareStatementPointcut();
	
	@Around("aroundPrepareStatementPointcut()")
	public Object aroundPrepareStatementAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		String sql = (String) joinPoint.getArgs()[0];
		PreparedStatement stmt = (PreparedStatement) joinPoint.proceed();
		contexts.addStatement(stmt, sql);
		return stmt;
	}
	
	@Pointcut
	public abstract void aroundPrepareCallPointcut();
	
	@Around("aroundPrepareCallPointcut()")
	public Object aroundPrepareCallAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		String sql = (String) joinPoint.getArgs()[0];
		CallableStatement stmt = (CallableStatement) joinPoint.proceed();
		contexts.addStatement(stmt, sql);
		return stmt;
	}
	
	@Pointcut
	public abstract void beforeStatementClosePointcut();
	
	@Around("beforeStatementClosePointcut()")
	public Object beforeStatementCloseAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
		//System.out.println("before statement close " + joinPoint.getTarget());
		Statement stmt = (Statement) joinPoint.getTarget();
		
		contexts.closeStatement(stmt);
		
		return joinPoint.proceed();
	}	
}
